{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Adversarial Robustness Toolbox (ART) and scikit-learn Pipeline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook contains an example of generating adversarial samples using a black-box attack against a scikit-learn pipeline consisting of principal component analysis (PCA) and a support vector machine classifier (SVC), but any other valid pipeline would work too. The pipeline is first optimised using grid search with cross validation. The adversarial samples are created with black-box `HopSkipJump` attack. The training data is MNIST, because of its intuitive visualisation, but any other dataset including tabular data would be suitable too."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from sklearn import datasets\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.svm import SVC\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "from art.utils import load_dataset\n",
    "from art.estimators.classification import SklearnClassifier\n",
    "from art.attacks.evasion import HopSkipJump\n",
    "\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load the training and testing dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_features = 28*28\n",
    "(x_train, y_train), (x_test, y_test), _, _ = load_dataset('mnist')\n",
    "x_train = x_train.reshape((x_train.shape[0], n_features))\n",
    "x_test = x_test.reshape((x_test.shape[0], n_features))\n",
    "y_train = np.argmax(y_train, axis=1)\n",
    "y_test = np.argmax(y_test, axis=1)\n",
    "\n",
    "# Select a smaller set of samples to accelerate notebook example, remove for higher accuracy\n",
    "x_train = x_train[0:1000]\n",
    "x_test = x_test[0:100]\n",
    "y_train = y_train[0:1000]\n",
    "y_test = y_test[0:100]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create a pipeline containing PCA and SVC classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "svc = SVC(C=1.0, kernel='rbf')\n",
    "pca = PCA()\n",
    "pipeline = Pipeline(steps=[('pca', pca), ('svc', svc)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Grid search and cross validation to optimise number of PCA components and error term penalty"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best parameter (CV score=0.908):\n",
      "{'pca__n_components': 20, 'svc__C': 1.0}\n"
     ]
    }
   ],
   "source": [
    "param_grid = {'pca__n_components': [5, 20, 30, 40, 50, 64],\n",
    "              'svc__C': np.logspace(-4, 4, 5)}\n",
    "search = GridSearchCV(estimator=pipeline, param_grid=param_grid, iid=False, cv=5)\n",
    "search.fit(x_train, y_train)\n",
    "print(\"Best parameter (CV score=%0.3f):\" % search.best_score_)\n",
    "print(search.best_params_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create a black-box attack using ART"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "classifier = SklearnClassifier(model=search.best_estimator_)\n",
    "attack = HopSkipJump(classifier=classifier, targeted=False, norm=np.inf, max_iter=100, max_eval=100,\n",
    "                     init_eval=100, init_size=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Generate adversarial samples"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "107eee83bb884c938834dee7d981776f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(HTML(value='HopSkipJump'), FloatProgress(value=0.0), HTML(value='')))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "x_test_adv = attack.generate(x_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluate benign accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on benign test samples 91.0%:\n"
     ]
    }
   ],
   "source": [
    "accuracy_test_benign = search.score(x_test, y_test)\n",
    "print('Accuracy on benign test samples {}%:'.format(accuracy_test_benign * 100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluate adversarial accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy on adversarial test samples 5.0%:\n"
     ]
    }
   ],
   "source": [
    "accuracy_test_adversarial = search.score(x_test_adv, y_test)\n",
    "print('Accuracy on adversarial test samples {}%:'.format(accuracy_test_adversarial * 100))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspect a benign test sample"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 288x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.matshow(x_test[0].reshape((28, 28)));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predicted label: 7\n"
     ]
    }
   ],
   "source": [
    "print('Predicted label:', search.predict(x_test[0:1])[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspect an adversarial test sample"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 288x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.matshow(x_test_adv[0].reshape((28, 28)));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predicted label: 9\n"
     ]
    }
   ],
   "source": [
    "print('Predicted label:', search.predict(x_test_adv[0:1])[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "L_Infinity-norm: 0.2403459834117515\n"
     ]
    }
   ],
   "source": [
    "print('L_Infinity-norm:', np.linalg.norm(x_test_adv[0] - x_test[0], ord=np.inf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py37_tf220",
   "language": "python",
   "name": "py37_tf220"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
